﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;

using ProjectBase.Core;

using $prjsn$.Common.Validation;


namespace $safeprojectname$
{
    public class CollectionItemsHaveRequiredSettingsRule<TItem, TID, TValue> 
        : RuleBase, IValidationRule<TItem>
        where TItem : class, IPersistentObjectWithTypedId<TID>
    {
        #region members

        readonly Func<TItem, IEnumerable<TValue>> _compiledExpression;
        Func<TValue, bool> _predicate;
        string _requiredSetting;
        #endregion members

        #region Constructor
        public CollectionItemsHaveRequiredSettingsRule(Expression<Func<TItem, IEnumerable<TValue>>> expression)
        {
            var body = expression.Body as MemberExpression;
            if (body.IsNull())
            {
                throw new NotSupportedException(
                    "Provided 'Expression<Func<TItem, IEnumerable<TValue>>>' must be of a 'ExpressionType.MemberAccess' (UniqueCollectionItemRule). ");
            }
            PropertyName = body.Member.Name;
            _compiledExpression = expression.Compile();
        }
        #endregion Constructor

        #region Validate
        public virtual ValidationResult Validate(TItem entity, out ValidationMessage message)
        {
            message = null;

            var list = CompiledExpression.Invoke(entity);
            if (list.IsEmpty())
            {
                return ValidationResult.IsValid;
            }

            if (Predicate.Is())
            {
                return ValidatePredicate(ref message, list);
            }

            throw new ArgumentException("Rule was not correctly set, missing 'Predicate' delegate");
        }
        protected virtual ValidationResult ValidatePredicate(ref ValidationMessage message, IEnumerable<TValue> list)
        {
            foreach (var item in list)
            {
                var hasSetting = Predicate(item);
                if (!hasSetting)
                {
                    message = new ValidationMessage("The collection '{0}' contains item '{1}', with incorrect settings [{2}]")
                    {
                        PropertyName,
                        typeof(TValue).Name,
                        RequiredSetting,
                    };
                    return ValidationResult.Error;
                }
            }
            return ValidationResult.IsValid;
        }
        #endregion Validate

        #region Client
        public override IMDValidationRule GetMetaDataRule()
        {
            return null;
        }
        #endregion Client

        #region fluent
        public virtual CollectionItemsHaveRequiredSettingsRule<TItem, TID, TValue> HasSetting(Expression<Func<TValue, bool>> property)
        {
            _predicate = property.Compile();

            return this;
        }
        public virtual CollectionItemsHaveRequiredSettingsRule<TItem, TID, TValue> WithErrorMessage(string requiredSetting)
        {
            _requiredSetting = requiredSetting;
            return this;
        }
        #endregion fluent

        #region properties
        protected virtual Func<TItem, IEnumerable<TValue>> CompiledExpression { get { return _compiledExpression; } }
        protected virtual Func<TValue, bool> Predicate { get { return _predicate; } }

        protected virtual string RequiredSetting { get { return _requiredSetting; } }

        protected virtual bool? IsMultiple { get; set; }
        protected virtual string OverProperty { get; set; }
        protected virtual object UniqueValue { get; set; }
        #endregion properties

    }
}